﻿//Ben Gotthold
// Joe Illuminati
// CISC 360
// 9/23/2013
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace CISC_360_project
{
    public partial class Form1 : Form
    {
        private InstructionParser _IPR;
        private CPU _CPU;
        private bool _automate;

        public Form1()
        {
            InitializeComponent();
            _IPR = new InstructionParser();
            _CPU = new CPU();
            _CPU.PC.Data = 0;
            _automate = false;

            
            for (int i = 0; i < _CPU.memory.stack.Length; i++)
            {
                ListViewItem lvi = new ListViewItem(i.ToString());
                lvi.SubItems.Add(_CPU.memory.stack[i].ToString());
                listView1.Items.Add(lvi);
            }
            for (int i = 0; i < _CPU.memory.oneWayCache.GetLength(0); i++)
            {
                ListViewItem lvitwo = new ListViewItem();
                lvitwo.SubItems.Add(_CPU.memory.oneWayCache[i].tag.ToString());
                lvitwo.SubItems.Add(_CPU.memory.oneWayCache[i].data.ToString());
                lvitwo.SubItems.Add(_CPU.memory.oneWayCache[i].dirtyFlag.ToString());
                listView2.Items.Add(lvitwo);
            }

            for (int i = 0; i < _CPU.memory.twoWayCache.GetLength(0) *2; i++)
            {
                ListViewItem lvithree = new ListViewItem();

               
                lvithree.SubItems.Add((i/2).ToString());
                lvithree.SubItems.Add(_CPU.memory.twoWayCache[(i/2)].blocks[(i%2)].tag.ToString());
                lvithree.SubItems.Add(_CPU.memory.twoWayCache[(i / 2)].blocks[(i % 2)].data.ToString());
                lvithree.SubItems.Add(_CPU.memory.twoWayCache[(i / 2)].blocks[(i % 2)].dirtyFlag.ToString());
            
                listView3.Items.Add(lvithree);
            }    
        }

        private void load_button_Click(object sender, EventArgs e)
        {

            _CPU.Dispose();
            _CPU = new CPU();
            _CPU.PC.Data = 0;
            for (int i = 0; i < 2; i++)
            {
                using (var ofd = new OpenFileDialog())
                using (var sfd = new SaveFileDialog())
                {

                    // Only allows .s files to be opened and .dat files to be saved
                    ofd.Filter = "Assembly File|*.s";
                    sfd.Filter = "Binary File|*.bin";
                    sfd.Title = "Enter name of binary file";
                    // Was the OpenFileDialog Window opened successfully?
                    if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        try
                        {
                            String file_name = ofd.FileName;
                            String binary_file;
                            _IPR.loadAssemblyFile(file_name);
                            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                            {
                                binary_file = sfd.FileName;
                                _IPR.createBinary(binary_file);
                                _CPU.memory.loadInstructions(binary_file);
                                // Context Switching
                                _CPU.memory.loadProcess(binary_file, _IPR.TEXT, _CPU);
                            }

                            _CPU.memory.Text = _IPR.TEXT;
                            _CPU.memory.used_memory = _IPR.USED_MEMORY_ADDRESSES;
                            _CPU.memory.stack_frame.Clear();
                            _CPU.PC.Data = 0;
                            _CPU.Acc.Data = 0;                                  // reset a bunch of data 
                            _CPU.CC.Data = 0;
                            _CPU.memory.fromSpacial = 0;
                            _CPU.memory.cacheHit = 0;
                            _CPU.memory.cacheMiss = 0;
                            _CPU.memory.memAccess = 0;
                            _CPU.totalStallCount = 0;


                            richTextBox1.Text = "Assembly file load successful.";
                            updateRegesters();
                            updateMemory();
                            oneWayCache.Visible = true;
                            twoWayCache.Visible = true;
                            label5.Visible = true;

                        }
                        catch (Exception err)
                        {
                            MessageBox.Show(err.ToString());
                            richTextBox1.Text = "Assembly file load unsuccessful.";
                        }
                    }

                }
            }
            _CPU.memory.cycles_until_switch = Prompt.showDialog("Enter number of cycles to run until context switching", "Context Switching");
        }

        private void next_inst_but_Click(object sender, EventArgs e)
        {
            if (_IPR.ASSEMBLY_FILE != null && _CPU.PC.Data < _CPU.memory.Text.Count)
            {
                if (_CPU.branchStall)
                {
                    richTextBox1.Text = "Stalling on Branch";
                }
                else if (_CPU.decodeStall)
                {
                    richTextBox1.Text = "Stalling on decode";
                }
                else if(_CPU.mulStall){
                    richTextBox1.Text = "Stalling on Mul/Div";
                }
                
                else
                {
                    richTextBox1.Text = _CPU.memory.processes[_CPU.memory.current_process].process.TEXT[_CPU.PC.Data].instruction + "\n" + "Operations On Cycle: " +
                        _CPU.numOpsForCurrentInstruction + "    Total # of Operations: " +
                        _CPU.totalNumOpsPreformed + "\n" + "Process Running: " + _CPU.memory.current_process.ToString() + "\n";
                    if (_CPU.storeDone)
                    {
                        richTextBox1.Text += "\n Store Occured";
                    }
                    if (_CPU.exeDone)
                    {
                        richTextBox1.Text += "\n Execute Occured";
                    }
                    if (_CPU.decodeDone)
                    {
                        richTextBox1.Text += "\n Decode Occured";
                    }
                    if (_CPU.fetchDone)
                    {
                        richTextBox1.Text += "\n Fetch Occured";
                    }
                    
                }
            }
            else
            {
                
                if (_CPU.ready_to_cycle)
                {
                   
                        richTextBox1.Text = "Running; PC temperarly out of bounds";
                    
                    
                }
                else
                {
                    richTextBox1.Text = "No file has been loaded yet.";
                }
                
            }

            try
            {
                _CPU.startExicutionCycle();
            }
            catch (Exception err)
            {
                MessageBox.Show(err.ToString());
            }

            updateRegesters();
            updateMemory();
            
        }

        private void show_but_Click(object sender, EventArgs e)
        {
            String text = "";
            foreach (Instruction i in _CPU.memory.Text)
            {
                text += i.instruction + "\n";
            }
            richTextBox1.Text = text;
        }

        public void updateRegesters()
        {
            registerA.Text = Convert.ToString(_CPU.A.Data);
            registerB.Text = Convert.ToString(_CPU.B.Data);
            registerAcc.Text = Convert.ToString(_CPU.Acc.Data);
            registerZero.Text = Convert.ToString(_CPU.Zero.Data);
            registerOne.Text = Convert.ToString(_CPU.One.Data);
            registerPC.Text = Convert.ToString(_CPU.PC.Data);
            registerMAR.Text = Convert.ToString(_CPU.MAR.Data);
            registerMDR.Text = Convert.ToString(_CPU.MDR.Data);
            registerTEMP.Text = Convert.ToString(_CPU.Temp.Data);
            registerIR.Text = Convert.ToString(_CPU.IR.Data);
            registerCC.Text = Convert.ToString(_CPU.CC.Data);
            regesterAccD.Text = Convert.ToString(_CPU.AccD.Data);
            regesterOvf.Text = Convert.ToString(_CPU.Ovf.Data);
        }

       
        public void updateMemory()
        {
            for (int i = 0; i < _CPU.memory.stack.Length; i++)
            {
                listView1.Items[i].SubItems[1].Text = _CPU.memory.stack[i].ToString();
            }
            for (int i = 0; i < _CPU.memory.oneWayCache.GetLength(0); i++)
            {
                
                listView2.Items[i].SubItems[0].Text = _CPU.memory.oneWayCache[i].tag.ToString();
                listView2.Items[i].SubItems[1].Text = _CPU.memory.oneWayCache[i].data.ToString();
                listView2.Items[i].SubItems[2].Text = _CPU.memory.oneWayCache[i].dirtyFlag.ToString();

            }
            for (int i = 0; i < _CPU.memory.twoWayCache.GetLength(0) *2; i++)
            {

             

                listView3.Items[i].SubItems[0].Text = (i/2).ToString();
                listView3.Items[i].SubItems[1].Text = _CPU.memory.twoWayCache[(i / 2)].blocks[(i % 2)].tag.ToString();
                listView3.Items[i].SubItems[2].Text = _CPU.memory.twoWayCache[(i / 2)].blocks[(i % 2)].data.ToString();
                listView3.Items[i].SubItems[3].Text = _CPU.memory.twoWayCache[(i / 2)].blocks[(i % 2)].dirtyFlag.ToString();
               

            }
            hitCount.Text = _CPU.memory.cacheHit.ToString();
            missCount.Text = _CPU.memory.cacheMiss.ToString();
            memCount.Text = _CPU.memory.memAccess.ToString();
            stallLbl.Text = _CPU.totalStallCount.ToString();
            cycleLabel.Text = (_CPU.memory.cycles_until_switch - _CPU.memory.current_cycle + 1).ToString();
            spatialLabel.Text = _CPU.memory.fromSpacial.ToString();
        }

        private void changeCacheType_Click(object sender, EventArgs e)
        {
            _CPU.oneWayCache = true;
            cacheLabel.Text = "Direct Map Cache";
            listView2.Visible = true;
            listView3.Visible = false;
            twoWayCache.Visible = false;
            oneWayCache.Visible = false;
            label5.Visible = false;    
        }

        private void twoWayCache_Click(object sender, EventArgs e)
        {
            _CPU.oneWayCache = false;
            cacheLabel.Text = "Two-Way Cache";
            listView2.Visible = false;
            listView3.Visible = true;
            twoWayCache.Visible = false;
            oneWayCache.Visible = false;
            label5.Visible = false;
        }

        private void automate_but_Click(object sender, EventArgs e)
        {
            _automate = !_automate;
            // Code for Process thread will go here.
        }

       

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _CPU.Dispose();
        }
    }  

  
}
